﻿// oooooooooooooooooooooooooooooooooooooooooooooooooooooooooo
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Mogre;
using MogreNewt;
using System.IO;


using System.Runtime.InteropServices;
using System.Threading;
using Win32;
using System.Xml.Serialization;



namespace MogreMicroscope
{

    public class MogreWindow
    {
        public Root root;
        public SceneManager sceneMgr;

        protected Camera camera;
        protected Viewport viewport;
        protected RenderWindow window;
        protected Point position;
        protected IntPtr hWnd;
        protected IntPtr hParent;

        protected MOIS.InputManager inputManager;
        protected MOIS.Keyboard inputKeyboard;
        protected MOIS.Mouse inputMouse;
        protected MOIS.JoyStick inputJoystick;
        protected MOIS.ForceFeedback inputForceFeedback;
        protected MOIS.ForceFeedback.Const_SupportedEffectList inputForceFeedbackSupportedEffectList;      

        protected int mEntityCount = 0;

        public delegate  void StatusUpdateHandler(object sender,string data);
        public event StatusUpdateHandler OnStatusChanged;
       

        SceneNode floorNode;
        World m_World;

        List<Primitive> bodies = new List<Primitive>();
        bool _isGravity = false;

        public bool IsGravity
        {
            get { return _isGravity; }
            set { _isGravity = value; }
        }

        bool _isMouseInRenderPanel = false;

        public bool IsMouseInRenderPanel
        {
            get { return _isMouseInRenderPanel; }
            set { _isMouseInRenderPanel = value; }
        }

        const int NEWTON_FRAMERATE = 60;


        float m_update = 1.0f / (float)NEWTON_FRAMERATE;
        float timer = 10.0f;
        float timer2 = 10.0f;
        float timer3 = 10;

        const float veryHeavy = 9999999.0f;
        MaterialPair matPair;

        bool quit = false;

        float dt = 0.01f;

        float t = 0.0f;
        float accumulator = 0.0f;
        float currentTime = 0.0f;

        static long start = 0;
        static long frequency = 0;
        //Render Timer
        System.Windows.Forms.Timer mRenderTimer = null;
        HiPerfTimer perfTimer;

        public MogreWindow(Point origin, IntPtr hWnd, IntPtr parent)
        {
            perfTimer = new HiPerfTimer();
            position = origin;
            this.hWnd = hWnd;
            hParent = parent;

            mRenderTimer = new System.Windows.Forms.Timer();
            mRenderTimer.Interval = 16;
            mRenderTimer.Enabled = true;
            mRenderTimer.Start();
            mRenderTimer.Tick += new EventHandler(mRenderTimer_Tick);
        }

        public void InitMogre()
        {

            //----------------------------------------------------- 
            // 1 enter ogre 
            //----------------------------------------------------- 
            root = new Root();

            //----------------------------------------------------- 
            // 2 configure resource paths
            //----------------------------------------------------- 
            ConfigFile cf = new ConfigFile();
            cf.Load("resources.cfg", "\t:=", true);

            // Go through all sections & settings in the file
            ConfigFile.SectionIterator seci = cf.GetSectionIterator();

            String secName, typeName, archName;

            // Normally we would use the foreach syntax, which enumerates the values, but in this case we need CurrentKey too;
            while (seci.MoveNext())
            {
                secName = seci.CurrentKey;
                ConfigFile.SettingsMultiMap settings = seci.Current;
                foreach (KeyValuePair<string, string> pair in settings)
                {
                    typeName = pair.Key;
                    archName = pair.Value;
                    ResourceGroupManager.Singleton.AddResourceLocation(archName, typeName, secName);
                }
            }

            //----------------------------------------------------- 
            // 3 Configures the application and creates the window
            //----------------------------------------------------- 
            bool foundit = false;
            foreach (RenderSystem rs in root.GetAvailableRenderers())
            {
                root.RenderSystem = rs;
                String rname = root.RenderSystem.Name;
                if (rname == "Direct3D9 Rendering Subsystem")
                //    if (rname == "OpenGL Rendering Subsystem")
                {
                    foundit = true;
                    break;
                }
            }

            if (!foundit)
            {
                return; //we didn't find it... Raise exception?
            }

            //we found it, we might as well use it!
            root.RenderSystem.SetConfigOption("Full Screen", "No");
            //root.RenderSystem.SetConfigOption("Video Mode", "640 x 480 @ 32-bit colour");
            root.RenderSystem.SetConfigOption("Video Mode", "1024 x 768 @ 32-bit colour");

            root.Initialise(false);
            NameValuePairList misc = new NameValuePairList();
            misc["externalWindowHandle"] = hWnd.ToString();
            window = root.CreateRenderWindow("Simple Mogre Form Window", 0, 0, false, misc);
            ResourceGroupManager.Singleton.InitialiseAllResourceGroups();




            //----------------------------------------------------- 
            // 4 Create the SceneManager
            // 
            //		ST_GENERIC = octree
            //		ST_EXTERIOR_CLOSE = simple terrain
            //		ST_EXTERIOR_FAR = nature terrain (depreciated)
            //		ST_EXTERIOR_REAL_FAR = paging landscape
            //		ST_INTERIOR = Quake3 BSP
            //----------------------------------------------------- 
            sceneMgr = root.CreateSceneManager(SceneType.ST_GENERIC, "SceneMgr");
            sceneMgr.AmbientLight = new ColourValue(0.5f, 0.5f, 0.5f);
            

            //----------------------------------------------------- 
            // 5 Create the camera 
            //----------------------------------------------------- 
            camera = sceneMgr.CreateCamera("SimpleCamera");
            



            // position camera
            //camera.SetPosition(0.0f, 250.0f, -5.0f);

            camera.Position = new Vector3(0f, 10f, 50.0f);

            // Look back along -Z
            camera.LookAt(new Vector3(0f, 0.0f, 0.0f));
            camera.NearClipDistance = 5;

            viewport = window.AddViewport(camera);
            viewport.BackgroundColour = new ColourValue(0.0f, 0.0f, 0.0f, 1.0f);

            camera.AspectRatio = ((float)viewport.ActualWidth / viewport.ActualHeight);





            // Newton Init
            Init_Newton();

            CreateSceneWorld();

            MogreNewt.CollisionPrimitives.TreeCollisionSceneParser stat_col = new MogreNewt.CollisionPrimitives.TreeCollisionSceneParser(m_World);
            stat_col.ParseScene(floorNode, true, mEntityCount++); //IHF true);
            //stat_col.ParseScene(node, true, 2); //IHF true);
            MogreNewt.Body bod = new MogreNewt.Body(m_World, stat_col);
            stat_col.Dispose();

            bod.AttachNode(floorNode);
            bod.UserData = floorNode.Name;
            //   bod.AttachNode(node);
            bod.SetPositionOrientation(new Vector3(0.0f, 0.0f, 0.0f), Quaternion.IDENTITY);


            CreateInput();

            sceneMgr._updateSceneGraph(camera);

            // SceneNode testNode = (SceneNode)nodeCraft;
            // AxisAlignedBox aab = testNode._getWorldAABB();

            // using the new "SceneParser" TreeCollision primitive.  this will automatically parse an entire tree of
            // SceneNodes (parsing all children), and add collision for all meshes in the tree.
          
        }

        public void Init_Newton()
        {
            // Newton initialization
            m_World = new World();
            m_World.SetWorldSize(new Vector3(-25000, -2, -25000), new Vector3(25000, 25000, 25000));
            m_World.DebuggerInstance.Init(sceneMgr);
            AxisAlignedBox aab = m_World.WorldSize;
            Console.WriteLine(aab);
            int v = m_World.Version;
            Console.WriteLine(""+v);
           
            
            //m_World.DebuggerInstance.ShowDebugInformation();

            matPair = new MaterialPair(m_World, m_World.DefaultMaterialID, m_World.DefaultMaterialID);
            // Callback instead of manual collision detection.
            matPair.SetContactCallback(new BodyContact(this));
            //matPair.SetContinuousCollisionMode(
            m_World.DebuggerInstance.SetDefaultColors(new ColourValue(1, 1, 0));

        } 

        public void CreateSceneWorld()
        {
            ColourValue skyColor = new ColourValue(0.6f, 0.7f, 0.8f);
            // Set ambient light and fog
            sceneMgr.AmbientLight = new ColourValue(1.0f, 1.0f, 1.0f, 0);
            // Create sun-light
            Light SunLight = sceneMgr.CreateLight("Sun");
            SunLight.Position = new Vector3(0, 10000, 0);
            SunLight.Type = Light.LightTypes.LT_DIRECTIONAL;
            SunLight.Direction = new Vector3(0, -1, -0.8f);

            // shadows on!
            sceneMgr.ShadowTechnique = ShadowTechnique.SHADOWTYPE_NONE;//.SHADOWTYPE_STENCIL_ADDITIVE;

            // sky box.
            sceneMgr.SetSkyBox(true, "Examples/CloudyNoonSkyBox");

            // Define a floor plane mesh
            Plane p;
            p.normal = Vector3.UNIT_Y;
            p.d = 0;
            //MeshManager.Singleton.CreatePlane("FloorPlane", ResourceGroupManager.DEFAULT_RESOURCE_GROUP_NAME, p, 20000000F, 2000000F, 20, 20, true, 1, 50F, 50F, Vector3.UNIT_Z);
            MeshManager.Singleton.CreatePlane("FloorPlane", ResourceGroupManager.DEFAULT_RESOURCE_GROUP_NAME, p, 30000F, 30000F, 20, 20, true, 1, 50F, 50F, Vector3.UNIT_Z);
            //bod.SetPositionOrientation(new Vector3(0.0f, -20.0f, 0.0f), Quaternion.IDENTITY);

            Entity floor;
            // Create an entity (the floor)
            floor = sceneMgr.CreateEntity("floor", "FloorPlane");
            //floor.SetMaterialName("Examples/BlueGrid");// ("Examples/SpaceSkyPlane");
            floor.SetMaterialName("Examples/GrassFloor");

            floorNode = sceneMgr.RootSceneNode.CreateChildSceneNode("Floor");
            floorNode.AttachObject(floor);
            floor.CastShadows = false;
            floorNode.SetVisible(true);
            floorNode.SetPosition(0.0f, 0.0f, 0.0f);
//            sceneMgr._updateSceneGraph(camera);
  //          AxisAlignedBox aab = floorNode._getWorldAABB();
        }


        public Body CreateCompoundObject(string name, string filename, string matName,Vector3 pos,Quaternion rot,Vector3 scale,float mass,bool gravity,bool AAB_based)
        {
            Entity ent = sceneMgr.CreateEntity(name + mEntityCount, filename);
            ent.SetMaterialName(matName);
            SceneNode node = sceneMgr.RootSceneNode.CreateChildSceneNode(name + "Node" + mEntityCount++);

            node.AttachObject(ent);
            ent.CastShadows = true;
            //node.ShowBoundingBox = true;
            node.SetVisible(true);
            node.SetScale(scale);
            node.Position = Vector3.ZERO;

            Console.WriteLine(name);
            List<VertsWrapper> verts = new List<VertsWrapper>();
            if (AAB_based == true)
            {
                verts = MeshUtils.GetMeshVerticesAsBoxes(ent.GetMesh(), scale);
            }
            else
            {
                verts = MeshUtils.GetMeshVertices(ent.GetMesh(), scale);
            }
           

            MogreNewt.Collision[] cp = new MogreNewt.Collision[verts.Count];
            int loop = 0;

            foreach (VertsWrapper item in verts)
            {
                if (AAB_based == true)
                {
                    if (item.Rotation != Quaternion.ZERO)
                    {
                        cp[loop] = new MogreNewt.CollisionPrimitives.Box(m_World, item.AAB.Size, item.Rotation, item.AAB.Center, loop++);
                    }
                    else
                    {
                        cp[loop] = new MogreNewt.CollisionPrimitives.Box(m_World, item.AAB.Size, item.AAB.Center, loop++);
                    }
                    
                }
                else
                {
                    cp[loop] = new MogreNewt.CollisionPrimitives.ConvexHull(m_World, item.vertices, 217.0f, loop++);
                }
            }
            MogreNewt.Collision col = new MogreNewt.CollisionPrimitives.CompoundCollision(m_World, cp, 10);


            Vector3 inertia = Vector3.ZERO;
            Vector3 offset = Vector3.ZERO;


            inertia = Vector3.UNIT_SCALE;
            inertia = inertia * mass;
            Body bod = new MogreNewt.Body(m_World, col);
            col.Dispose();


            bod.AttachNode(node);
            bod.SetMassMatrix(mass, inertia);
            bod.UserData = name;
            bod.IsGravityEnabled = gravity;
            bod.SetPositionOrientation(pos, rot);
            return bod;
        }

        #region PRIMITIVE_INTERFACE

        public void RebuildBodies(Primitive prim)
        {
            prim.RebuildBody(m_World, sceneMgr);
        }
        public Primitive CreateCollisionPrimitive(string name, CollisionType colType,Vector3 pos, Quaternion rot, Vector3 scale, float mass, bool gravity)
        {
            
            MogreNewt.Collision cp=null;

            switch (colType)
            {
                
                case CollisionType.Capsule:
                    cp = new MogreNewt.CollisionPrimitives.Capsule(m_World, scale.x, scale.y, bodies.Count);
                    break;
                case CollisionType.ChamferCylinder:
                    cp = new MogreNewt.CollisionPrimitives.ChamferCylinder(m_World, scale.x, scale.y, bodies.Count);
                    break;
                case CollisionType.Cone:
                    cp = new MogreNewt.CollisionPrimitives.Cone(m_World, scale.x, scale.y, bodies.Count);
                    break;
                case CollisionType.Cylinder:
                    cp = new MogreNewt.CollisionPrimitives.Cylinder(m_World, scale.x, scale.y, bodies.Count);
                    break;
                case CollisionType.Ellipsoid:
                    cp = new MogreNewt.CollisionPrimitives.Ellipsoid(m_World, scale, bodies.Count);
                    break;
                default:
                    cp = new MogreNewt.CollisionPrimitives.Box(m_World, scale, bodies.Count);
                    break;
            }
           


            Vector3 inertia = Vector3.ZERO;
            Vector3 offset = Vector3.ZERO;


            inertia = Vector3.UNIT_SCALE;
            inertia = inertia * mass;
            Body bod = new MogreNewt.Body(m_World, cp);
            cp.Dispose();
            bod.SetMassMatrix(mass, inertia);
            bod.UserData = name;
            bod.IsGravityEnabled = gravity;
            bod.SetPositionOrientation(pos, rot);
            
            Primitive prim = new Primitive(mEntityCount, name + mEntityCount++, bod, colType,pos, rot, scale);
            prim.Mass = mass;
            bodies.Add(prim);
            return prim;
        }

        private Body BuildCompoundObjectFromSceneNode(ref Primitive prim)
        {
            MovableObject movObj = prim.Node.GetAttachedObject(0);
            if (movObj != null)
            {
                Entity ent = (Entity)movObj;

                List<VertsWrapper> verts = new List<VertsWrapper>();

                verts = MeshUtils.GetMeshVerticesAsBoxes(ent.GetMesh(), prim.Node.GetScale());

                MogreNewt.Collision[] cp = new MogreNewt.Collision[verts.Count];
                int loop = 0;

                Console.WriteLine(prim.Node._getWorldAABB().Center + " " + prim.Node._getWorldAABB().Size);

                foreach (VertsWrapper item in verts)
                {
                   
                    Console.WriteLine("CCCCCCC ----------------------------------------------------------");
                    Console.WriteLine(item.AAB.Size + " " + item.AAB.Center );
                    MogreNewt.CollisionPrimitives.Box bx = new MogreNewt.CollisionPrimitives.Box(m_World, item.AAB.Size, item.AAB.Center, 0);
                    //Body bd = new MogreNewt.Body(m_World, bx);
                    ConvexCollisionItem cci = new ConvexCollisionItem(item.AAB.Size, item.AAB.Center,Quaternion.IDENTITY, bx);
                    prim.Cols.Add(cci);
                    cp[loop++] = bx;
                }
                MogreNewt.Collision col = new MogreNewt.CollisionPrimitives.CompoundCollision(m_World, cp, 10);

                
                Vector3 inertia = Vector3.ZERO;
                Vector3 offset = Vector3.ZERO;


                inertia = Vector3.UNIT_SCALE;
                inertia = inertia * 100;
                Body bod = new MogreNewt.Body(m_World, col);
                col.Dispose();


                bod.AttachNode(prim.Node);
                bod.SetMassMatrix(100, inertia);
                bod.UserData = prim.Node.Name;
                bod.IsGravityEnabled = true;
                bod.SetPositionOrientation(prim.Node.Position, prim.Node.Orientation);
                return bod;
            }
            return null;
        }

        public Primitive CreateCompoundObjectFromSceneNode(SceneNode node)
        {
            Primitive prim = new Primitive(mEntityCount, node.Name + mEntityCount++,PrimitiveType.CompoundCol);
            prim.Node = node;
            prim.Body = BuildCompoundObjectFromSceneNode(ref prim);
            bodies.Add(prim);
            return prim;
        }

        public Primitive[] DeconstructCompoundFromPrimitive(Primitive prim)
        {
            List<Primitive> prims = new List<Primitive>();
         
            Vector3 pos = prim.Position;
            Quaternion orient = prim.Orientation;
            if (prim.Node != null)
            {
                Primitive res = new Primitive(mEntityCount, prim.Node.Name + mEntityCount++, prim.Node, prim.Node.Position, prim.Node.Orientation, prim.Node.GetScale());
                prims.Add(res);
            }



            foreach (Primitive prim1 in prim.BodyCols)
            {
                prim1.RebuildBody(m_World, sceneMgr);
           
            }
            prims.AddRange(prim.BodyCols);
            prim.BodyCols.Clear();
            if (prim.Body != null)
            {
                prim.Body.Dispose();
                prim.Body = null;

            }
           

            
            Console.WriteLine("------------------------- " + prim.Position);
            foreach (ConvexCollisionItem col in prim.Cols)
            {
                Body bod = new Body(m_World, col.Col);
                
                
                bod.SetPositionOrientation(pos + (col.Position), col.Orientation);
                Primitive res = null;
                if (col.Col.GetType() == typeof(MogreNewt.CollisionPrimitives.Box))
                {
                    res = new Primitive(mEntityCount, "compBod_Box" + mEntityCount++, bod, CollisionType.Box, pos + col.Position, col.Orientation, col.Size);
                    continue;
                }
                if (col.GetType() == typeof(MogreNewt.CollisionPrimitives.Capsule))
                {
                    res = new Primitive(mEntityCount, "compBod_Capsule" + mEntityCount++, bod, CollisionType.Capsule, pos + col.Position, col.Orientation, col.Size);
                    continue;
                }
                if (col.GetType() == typeof(MogreNewt.CollisionPrimitives.ChamferCylinder))
                {
                    res = new Primitive(mEntityCount, "compBod_ChamferCylinder" + mEntityCount++, bod, CollisionType.ChamferCylinder, pos + col.Position, col.Orientation, col.Size);
                    continue;
                }
                if (col.GetType() == typeof(MogreNewt.CollisionPrimitives.Cone))
                {
                    res = new Primitive(mEntityCount, "compBod_Cone" + mEntityCount++, bod, CollisionType.Cone, pos + col.Position, col.Orientation, col.Size);
                    continue;
                }

                if (col.GetType() == typeof(MogreNewt.CollisionPrimitives.Cylinder))
                {
                    res = new Primitive(mEntityCount, "compBod_Cylinder" + mEntityCount++, bod, CollisionType.Cylinder, pos + col.Position, col.Orientation, col.Size);
                    continue;
                }

                if (col.GetType() == typeof(MogreNewt.CollisionPrimitives.Ellipsoid))
                {
                    res = new Primitive(mEntityCount, "compBod_Ellipsoid" + mEntityCount++, bod, CollisionType.Ellipsoid, pos + col.Position, col.Orientation, col.Size);
                    continue;
                }

                prims.Add(res);
            }
            prim.Cols.Clear();



            if (prims.Count > 0)
            {
                prim.Dispose();
                prim = null;
                bodies.AddRange(prims);
                return prims.ToArray();
            }
            return null;
        }

        public Primitive CreateComplexCollision(string name, PrimitiveType type)
        {

            Primitive prim = new Primitive(mEntityCount, name + mEntityCount++,type);
            bodies.Add(prim);
            return prim;
        }

        public void BuildConvexHull(Primitive prim, SceneNode node)
        {
            prim.CreateConvexHull(m_World, node);
        }

        public void BuildTree(Primitive prim, SceneNode node)
        {
            prim.CreateTree(m_World, node);
        }

        public void BuildCompound(Primitive prim, ref Primitive[] cols, SceneNode node)
        {
            prim.CreateCompound(m_World, ref cols,node);
            
            
        }

        public Primitive AddClone(Primitive prim1)
        {
            Primitive prim;
            if (prim1.IsBody())
            {
                prim = AddCollisionPrimitive(prim1.Name, prim1.PrimTypeToColTypeConverter(prim1.PrimitiveClass), prim1.Position, prim1.Orientation, prim1.Scale, prim1.Mass, true);
            }
            else
            {
                Entity ent = sceneMgr.CreateEntity(prim1.Name + mEntityCount, prim1.Name);
                ent.SetMaterialName("1___Default");
                SceneNode node = sceneMgr.RootSceneNode.CreateChildSceneNode(prim1.Name + "Node" + mEntityCount);

                node.AttachObject(ent);
                ent.CastShadows = true;
                //node.ShowBoundingBox = true;
                node.SetVisible(true);
                node.SetScale(prim1.Scale);
                node.Position = prim1.Position;
                node.Orientation = prim1.Orientation;
                prim = new Primitive(mEntityCount, prim1.Name + mEntityCount, node, prim1.Position, prim1.Orientation, prim1.Scale);
            }
            bodies.Add(prim);
            mEntityCount++;
            return prim;
        }

        public Primitive LoadMesh(string filename, Vector3 pos, Quaternion rot, Vector3 scale)
        {

            string meshName = Path.GetFileNameWithoutExtension(filename);
            unsafe
            {
                System.IO.FileStream pFile = System.IO.File.Open(filename, System.IO.FileMode.Open);
                MeshPtr pMesh = MeshManager.Singleton.CreateManual(meshName, ResourceGroupManager.DEFAULT_RESOURCE_GROUP_NAME);
                DataStreamPtr stream = new DataStreamPtr(new ManagedDataStream(pFile));
                new MeshSerializer().ImportMesh(stream, pMesh);
               // MeshManager.Singleton.Load(filename, ResourceGroupManager.DEFAULT_RESOURCE_GROUP_NAME);
                stream.Close();
                pFile.Close();

            }

            Entity ent = sceneMgr.CreateEntity(meshName + mEntityCount, meshName);
            ent.SetMaterialName("1___Default");
            SceneNode node = sceneMgr.RootSceneNode.CreateChildSceneNode(meshName + "Node" + mEntityCount);

            node.AttachObject(ent);
            ent.CastShadows = true;
            //node.ShowBoundingBox = true;
            node.SetVisible(true);
            node.SetScale(scale);
            node.Position = pos;
            node.Orientation = rot;

            Primitive prim = new Primitive(mEntityCount, meshName + mEntityCount++, node, pos, rot, scale);
            bodies.Add(prim);
            return prim;

         
        }

        public Primitive AddCollisionPrimitive(string name, CollisionType colType, Vector3 pos, Quaternion rot, Vector3 scale, float mass, bool gravity)
        {

            return CreateCollisionPrimitive(name, colType, pos, rot, scale, mass, gravity);
           
        }

        public Primitive AddComplexCollision(string name,PrimitiveType type)
        {

            return CreateComplexCollision(name, type);

        }

        public void ExportCollision(Primitive prim,string filename)
        {
            string ext = Path.GetExtension(filename);
            FileStream fs = File.Create(filename);

            try
            {
                if (ext.Contains("xml"))
                {
                    // write out prim data
                    XmlSerializer serXml = new XmlSerializer(typeof(Primitive));
                    prim.Serialising = true;
                    serXml.Serialize(fs, prim);
                    prim.Serialising = false;
                }
                else
                {
                    MogreNewt.CollisionSerializer ser = new CollisionSerializer();



                    ser.ExportCollision(prim.Body.Collision, fs);

                }
            }
            catch { }
            fs.Close();
            fs.Dispose();
        }

        public void ImportCollision(ref Primitive prim,string filename)
        {
            string ext = Path.GetExtension(filename);
            FileStream fs = File.OpenRead(filename);

            try
            {
                if (ext.Contains("xml"))
                {

                    XmlSerializer serXml = new XmlSerializer(typeof(Primitive));
                    prim.Serialising = true;
                    prim = (Primitive)serXml.Deserialize(fs);
                    prim.Index = mEntityCount++;
                    bodies.Add(prim);
                    foreach (Primitive item in prim.BodyCols)
                    {
                        item.Index = mEntityCount++;
                        bodies.Add(item);
                    }
                    prim.Serialising = false;
                }
                else
                {
                    MogreNewt.CollisionSerializer ser = new CollisionSerializer();
                    ser.ImportCollision(fs, prim.Body.Collision);
                }
            }
            catch(Exception ex)
            {
                Console.WriteLine(ex.Message);
            }

            fs.Close();
            fs.Dispose();
        }
    
        public void SetPrimitivePositionOrientation(int Id,Vector3 pos,Quaternion orient)
        {
            Primitive item = null;
            item = bodies.Find(delegate(Primitive o) { return o.Index == Id; });
            if (item != null)
            {
                item.Position = pos;
                item.Orientation = orient;

                if (item.IsBody())
                {
                    m_World.InvalidateCache();
                }
            }
        }

        public PrimitiveType GetPrimitiveType(int Id)
        {
            Primitive item = null;
            item = bodies.Find(delegate(Primitive o) { return o.Index == Id; });
            if (item != null)
            {
                return item.PrimitiveClass;
            }
            return PrimitiveType.Undefined;
        }

        public Primitive GetPrimitive(int Id)
        {
            Primitive item = null;
            item = bodies.Find(delegate(Primitive o) { return o.Index == Id; });
            return item;
        }

        public Vector3 GetPrimitivePosition(int Id)
        {
            Vector3 pos = Vector3.ZERO;
            //Quaternion orient;
            Primitive item = null;
            item = bodies.Find(delegate(Primitive o) { return o.Index == Id; });
            if (item != null)
            {
                pos = item.Position;
            }
            //bodies[Id].Body.GetPositionOrientation(out pos, out orient);
            return pos;
        }

        public Quaternion GetPrimitiveOrientation(int Id)
        {
            //Vector3 pos;
            Quaternion orient = Quaternion.IDENTITY;
            Primitive item = null;
            item = bodies.Find(delegate(Primitive o) { return o.Index == Id; });
            if (item != null)
            {
               // pos = item.Position;
                orient = item.Orientation;
            }
            //bodies[Id].Body.GetPositionOrientation(out pos, out orient);
            return orient;

        }

        public Vector3 GetPrimitiveScale(int Id)
        {
            Primitive item = null;
            item = bodies.Find(delegate(Primitive o) { return o.Index == Id; });
            if (item != null)
            {
                return item.Scale;
            }
            return Vector3.UNIT_SCALE;
        }

        public void RenamePrimitive(int Id,string newName)
        {
            Primitive item = null;
            item = bodies.Find(delegate(Primitive o) { return o.Index == Id; });
            if (item != null)
            {
                item.DisplayName = newName;
            }
        }

        public void SetPrimitiveGravity(int Id, bool enabled)
        {
            Primitive item = null;
            item = bodies.Find(delegate(Primitive o) { return o.Index == Id; });
            if (item != null)
            {
                try
                {
                    if (item.IsBody())
                    {
                        item.Body.IsGravityEnabled = enabled;
                    }
                }
                catch { }
            }
        }

        public Vector3 SetPrimitiveScale(int Id,Vector3 newScale)
        {
            Primitive item = null;
            item = bodies.Find(delegate(Primitive o) { return o.Index == Id; });
            if (item != null)
            {
               item.Scale = newScale;
               try
               {
                   if (item.IsBody())
                   {
                       item.RefreshBodyWithScale(m_World, sceneMgr);
                   }
                   else
                   {
                       item.Node.Scale(newScale);
                   }
               }
               catch { }
               return item.Scale;

            }
            return Vector3.UNIT_SCALE;
        }

        public void RemovePrimitive(int Id)
        {
            Primitive item = null;
            item = bodies.Find(delegate(Primitive o) { return o.Index == Id; });
            if (item != null)
            {
                try
                {
                    if (item.IsNode())
                    {
                        if (sceneMgr.RootSceneNode.RemoveChild(item.Node) != null)
                        {
                            bodies.Remove(item);
                            item.Dispose();
                            item = null;
                        }
                    }
                    else
                    {
                        bodies.Remove(item);
                        item.Body.Dispose();
                        item = null;
                    }
                }
                catch { }
            }
        }

        public void RemoveComplexCollisionPrimitive(int Id)
        {
            Primitive item = null;
            item = bodies.Find(delegate(Primitive o) { return o.Index == Id; });
            if (item != null)
            {
                
            }
        }


        #endregion PRIMITIVE_INTERFACE


        #region CAMERA_HANDLING

        public void SetCameraPosition(Vector3 pos,Vector3 lookAt,Vector3 direction)
        {
            camera.Position = pos;
            camera.LookAt(lookAt);
            camera.Direction = direction;
            
        }

        public void SetCameraPosition(Vector3 pos)
        {
            camera.Position = pos;
        }

        public void PointCameraAt(Vector3 pos)
        {
            camera.LookAt(pos);
        }

        public Vector3 GetCameraPosition()
        {
            return camera.Position;
        }

        public void PointCameraDown()
        {
            camera.Pitch(new Radian(new Degree(-90)));
        }

        public void PointCameraLevel()
        {
            camera.Pitch(new Radian(new Degree(0)));
        }

        public void SetOrthoCamera()
        {
            //camera.OrientationMode = OrientationMode.
            camera.OrthoWindowHeight = viewport.ActualHeight;
            camera.OrthoWindowWidth = viewport.ActualWidth;
            camera.ProjectionType = ProjectionType.PT_ORTHOGRAPHIC;

        }

        #endregion CAMERA_HANDLING

        void mRenderTimer_Tick(object sender, EventArgs e)
        {
            float newTime = time();
            float deltaTime = newTime - currentTime;

            if (quit == false)
            {
                if (deltaTime > 0.0f)
                {
                    currentTime = newTime;

                    // update discrete time
                    accumulator += deltaTime;

                    while (accumulator >= dt)
                    {
                        accumulator -= dt;
                        t += dt;
                    }
                }
                this.DoRender();
            }
            else
            {
                mRenderTimer.Stop();
                Application.Exit();
            }
        }



        #region INPUT
        public virtual bool UseBufferedInput
        {
            get { return false; }
        }

        public virtual void CreateInput()
        {
            LogManager.Singleton.LogMessage("*** Initializing OIS ***");
            MOIS.ParamList param = new MOIS.ParamList();

            param.Insert("w32_mouse", "DISCL_NONEXCLUSIVE");
            param.Insert("w32_mouse", "DISCL_FOREGROUND");
            IntPtr windowHnd;
            window.GetCustomAttribute("WINDOW", out windowHnd);
            param.Insert("WINDOW", hParent.ToString()); //windowHnd.ToString());

            // Hook up the InputManager to the application window
            inputManager = MOIS.InputManager.CreateInputSystem(param);

            if (inputManager != null)
            {
                // Create the devices
                try
                {
                    inputKeyboard = (MOIS.Keyboard)inputManager.CreateInputObject(MOIS.Type.OISKeyboard, false);

                    inputMouse = (MOIS.Mouse)inputManager.CreateInputObject(MOIS.Type.OISMouse, false);
                   

                    try
                    {
                        inputJoystick = (MOIS.JoyStick)inputManager.CreateInputObject(MOIS.Type.OISJoyStick, true);
                       // Program.Instance.gameManager.hasJoy = true;
                        /*
                        try
                        {
                            mFF = (MOIS.ForceFeedback)mJoystick.QueryInterface(MOIS.Interface.IType.ForceFeedback);
                            mSupportedEffectList = mFF.GetSupportedEffects();

                        }
                        catch
                        {
                            //Console.WriteLine("No ForceFeedback");
                        }
                         */ 
                    }
                    catch
                    {
                       Console.WriteLine("No Joystick");
                    }



                }
                catch
                {
                    LogManager.Singleton.LogMessage(MOIS.OISException.LastException.eText);
                }

            }
        }

   
        Vector3 pos2 = Vector3.ZERO;
        Quaternion orient = Quaternion.ZERO;
        Vector3 newScale = Vector3.ZERO;


        Vector3 oldPos = Vector3.ZERO;
  
        int target = 0;
        bool lookAtHome = true;

        private void DoRender()
        {
            

            if (this.root != null)
            {
               // m_World.DebuggerInstance.ShowDebugInformation(false, true);
                m_World.DebuggerInstance.ShowDebugInformation(false, false);

                m_World.CollisionUpdate();
                if (_isGravity == true)
                {
                    m_World.Update(m_update);
                }
               


                if (lookAtHome == false)
                {
                   
                    if (bodies.Count > 0)
                    {
                        camera.LookAt(bodies[target].Position);
                    }
                }

                // Look back along -Z
                try
                {
                    // Capture all key presses since last check.
                    inputKeyboard.Capture();
                    if (_isMouseInRenderPanel == true)
                    {
                        inputMouse.Capture();
                    }
                    
                    if (inputKeyboard.IsKeyDown(MOIS.KeyCode.KC_ESCAPE))
                    {
                        quit = true;
                    }

                    if (inputKeyboard.IsKeyDown(MOIS.KeyCode.KC_LEFT))
                    {
                        camera.MoveRelative(Vector3.NEGATIVE_UNIT_X);
                    }

                    if (inputKeyboard.IsKeyDown(MOIS.KeyCode.KC_RIGHT))
                    {
                        camera.MoveRelative(Vector3.UNIT_X);
                    }

                    if (inputKeyboard.IsKeyDown(MOIS.KeyCode.KC_UP))
                    {
                        camera.MoveRelative(Vector3.UNIT_Y);
                    }

                    if (inputKeyboard.IsKeyDown(MOIS.KeyCode.KC_DOWN))
                    {
                        camera.MoveRelative(Vector3.NEGATIVE_UNIT_Y); 
                    }

                   

                    

                    if (inputMouse.MouseState.ButtonDown(MOIS.MouseButtonID.MB_Left))
                    {
                        if (inputMouse.MouseState.X.rel > 0)
                        {
                            camera.Yaw(new Radian(new Degree(-1)));
                        }
                        if (inputMouse.MouseState.X.rel < 0)
                        {
                            camera.Yaw(new Radian(new Degree(1)));
                        }

                       
                    }
                    if (inputMouse.MouseState.Z.rel > 0)
                    {
                        int multi = 1;
                        if (inputMouse.MouseState.ButtonDown(MOIS.MouseButtonID.MB_Right))
                        {
                            multi = 10;
                        }
                        camera.MoveRelative(Vector3.UNIT_Z*multi);
                    }
                    if (inputMouse.MouseState.Z.rel < 0)
                    {
                        int multi = 1;
                        if (inputMouse.MouseState.ButtonDown(MOIS.MouseButtonID.MB_Right))
                        {
                            multi = 10;
                        }
                        camera.MoveRelative(Vector3.NEGATIVE_UNIT_Z*multi);
                    }

                    if (inputMouse.MouseState.ButtonDown(MOIS.MouseButtonID.MB_Right))
                    {
                       

                    }
                    if (inputKeyboard.IsKeyDown(MOIS.KeyCode.KC_SPACE))
                    {
                        if (timer2 <= 0.0f)
                        {
                            // now "shoot" an object!
                            // we get the position and direction from the camera...
                            Body body = MakePrimitiveShape(new Vector3(0.5f, 0.5f, 0.5f), camera.Position, camera.Orientation, ShotType.Box);

                            // set the initial orientation and velocity!
                            camera.DerivedDirection.Normalise();
                            body.Velocity = camera.DerivedDirection * 280.0f;

                            timer2 = 20.0f;
                        }

                    }
                    
                }
                catch (Exception inpEx)
                {
                    Console.WriteLine(inpEx.Message);
                }



                timer--;
                timer2--;
                timer3--;

                //// MOIS.MouseState_NativePtr mouseState = inputMouse.MouseState;
                try
                {
                    bool Temp = root.RenderOneFrame();
                }
                catch { }
            }

        }




   
        #endregion INPUT




        public void Dispose()
        {
            if (root != null)
            {
                root.Dispose();
                root = null;
            }
            if (inputManager != null)
            {
                inputManager.Dispose();
                inputManager = null;
            }
        }

        public float time()
        {
            perfTimer.Start();
            Thread.Sleep(0);
            perfTimer.Stop();
            if (start == 0)
            {
                start = perfTimer.Current();
                frequency = perfTimer.Frequency();
                return 0.0f;
            }
            long counter = perfTimer.Current();
            return (float)((counter - start) / (double)(frequency));
        }

        public void UpdateStatus(string value)
        {
            if (OnStatusChanged != null)
            {
                OnStatusChanged(this, value);
            }
        }


        #region MISC_UTILITIES

        bool particled = false;
        ParticleSystem ps;
        ParticleEmitter pe;
        void ShowSmoke(Vector3 pos)
        {
            /*
            ParticleSystem partSys = sceneMgr.CreateParticleSystem("TestParticles", 20);
            Particle p = partSys.CreateParticle();
            p.particleType = Particle.ParticleType.Visual;
             * */

            if (particled == false)
            {
                particled = true;
                MaterialPtr mat = MaterialManager.Singleton.Create("mat", ResourceGroupManager.DEFAULT_RESOURCE_GROUP_NAME);
                Pass p = mat.GetTechnique(0).GetPass(0);
                p.SetSceneBlending(SceneBlendType.SBT_TRANSPARENT_ALPHA);
                p.DepthWriteEnabled = false;
                p.LightingEnabled = false;
                p.CreateTextureUnitState("smoke.png");

                
                ps = sceneMgr.CreateParticleSystem("Smoke");
                ps.ParticleQuota = 500;
                ps.Visible = true;
                ps.CullIndividually = true;
                ps.DefaultWidth = 5;
                ps.DefaultHeight = 5;
                ps.SetMaterialName(mat.Name);


                pe = ps.AddEmitter("Point");

                ps.AddAffector("ColourImage").SetParameter("image", "smokecolors.png");

                sceneMgr.RootSceneNode.CreateChildSceneNode().AttachObject(ps);

                pe.Name = "SmokeEmitter";
                pe.ParticleVelocity = 5;
                pe.Direction = Vector3.UNIT_Y;
                pe.Position = pos;
                pe.MinParticleVelocity = 6;
                pe.MaxParticleVelocity = 8;
                pe.Angle = 0.25f;
                pe.TimeToLive = 20;
            }
            else
            {
                pe.Name = "SmokeEmitter";
                pe.ParticleVelocity = 5;
                pe.Direction = Vector3.UNIT_Y;
                pe.Position = pos;
                pe.MinParticleVelocity = 6;
                pe.MaxParticleVelocity = 8;
                pe.Angle = 0.25f;
                pe.TimeToLive = 20;
            }
            /*
            Overlay thisOverlay = new Overlay("myOverlay");
            OverlayContainer oc = OverlayContainer.();
            oc.Caption = "Hello";
            
            
            thisOverlay.Add2D(oc);
            thisOverlay.Show();
             */ 
        }

        Body MakeSimpleBox(Vector3 size, Vector3 pos, Quaternion orient)
        {
            // base mass on the size of the object.
            float mass = size.x * size.y * size.z * 2.5f;

            // calculate the inertia based on box formula and mass
            Vector3 inertia;
            Vector3 offset;


            Entity box1;
            SceneNode box1node;
            string name = "Box" + (mEntityCount++);
            box1 = sceneMgr.CreateEntity(name, "box.mesh");
            box1node = sceneMgr.RootSceneNode.CreateChildSceneNode();
            box1node.AttachObject(box1);
            box1node.SetScale(size);
            //box1node.ShowBoundingBox = true;
            //box1.NormaliseNormals = true;

            MogreNewt.ConvexCollision col = new MogreNewt.CollisionPrimitives.Box(m_World, size, 0);
            col.CalculateInertialMatrix(out inertia, out offset);
            inertia = inertia * mass;
            MogreNewt.Body bod = new MogreNewt.Body(m_World, col);
            col.Dispose();

            bod.AttachNode(box1node);
            bod.SetMassMatrix(mass, inertia);
            bod.IsGravityEnabled = true;

            box1.SetMaterialName("Examples/10PointBlock");
            bod.UserData = name;
            //bod.ForceCallback +=new ForceCallbackHandler(bod_ForceCallback);
            //bod.Transformed +=new TransformEventHandler(bod_Transformed);
            bod.SetPositionOrientation(pos, orient);
            box1node.SetVisible(false);
            return bod;
        }

        enum ShotType
        {
            Tetra = 0,
            Pyramid,
            Box
        }

        Body MakePrimitiveShape(Vector3 size, Vector3 pos, Quaternion orient,ShotType type) // 0 = tetra,1=bipyri,2=pyramid
        {
            // base mass on the size of the object.
            float mass = size.x * size.y * size.z * 2.5f;

            // calculate the inertia based on box formula and mass
            Vector3 inertia;
            Vector3 offset;


            Entity box1;
            SceneNode box1node;
            string name;
            switch(type)
            {
                case ShotType.Tetra:
                    name = "Tetra" + (mEntityCount++);
                    box1 = sceneMgr.CreateEntity(name, "Tetra.mesh");
                    box1.SetMaterialName("Ians_Primitives/Tetra");
                    break;
                case ShotType.Pyramid:
                    name = "Pyramid" + (mEntityCount++);
                    box1 = sceneMgr.CreateEntity(name, "Pyramid.mesh");
                    box1.SetMaterialName("Ians_Primitives/pyramid");
                    break;

                  
                default:
                    name = "Box" + (mEntityCount++);
                    box1 = sceneMgr.CreateEntity(name, "Box.mesh");
                    box1.SetMaterialName("Examples/10PointBlock");
                    break;
            }
            
            
            box1node = sceneMgr.RootSceneNode.CreateChildSceneNode();
            box1node.AttachObject(box1);
            box1node.SetScale(size);
           

            MogreNewt.ConvexCollision col = new MogreNewt.CollisionPrimitives.Box(m_World, size, 0);
            col.CalculateInertialMatrix(out inertia, out offset);
            inertia = inertia * mass;
            MogreNewt.Body bod = new MogreNewt.Body(m_World, col);
            col.Dispose();

            bod.AttachNode(box1node);
            bod.SetMassMatrix(mass, inertia);
            bod.IsGravityEnabled = true;
            bod.UserData = name;
            bod.SetPositionOrientation(pos, orient);
            box1node.SetVisible(true);
            return bod;
        }

        public bool ClickedOnPrimitive(int mx, int my)
        {
            //normalise mouse coordinates to [0,1]
            //we could have used the panel's width/height in pixels instead of viewport's width/height
            float scrx = (float)mx / viewport.ActualWidth;
            float scry = (float)my / viewport.ActualHeight;

            Ray ray = camera.GetCameraToViewportRay(scrx, scry);
            RaySceneQuery query = sceneMgr.CreateRayQuery(ray);
            RaySceneQueryResult results = query.Execute();

            foreach (RaySceneQueryResultEntry entry in results)
            {
                // Do stuff with the objects that intersect the ray
                Console.WriteLine("" + entry.movable.Name + "  " + entry.movable.MovableType);
            }

            //if we hit the head then there is 1 result
            if (results.Count > 0)
            {

                return true;
            }

            return false;
        }
        #endregion MISC_UTILITIES


        #region ROTATION_UTILITY
        public Quaternion RotateAxis(Quaternion orient, Vector3 axis, float fAngle)
        {
            Quaternion rotation = orient;
            rotation.FromAngleAxis(fAngle, TransformVector(orient, axis));
            orient *= rotation;
            return orient;
        }

        private Vector3 TransformVector(Quaternion Orientation, Vector3 Axis)
        {
            Vector3 vNewAxis;
            // Build a matrix from the quaternion.
            Matrix3 matRotation = Orientation.ToRotationMatrix();


            // Transform the queried axis vector by the matrix.
            vNewAxis.x = Axis.x * matRotation.m00 + Axis.y * matRotation.m10 + Axis.z * matRotation.m20;// + matRotation._41;
            vNewAxis.y = Axis.x * matRotation.m01 + Axis.y * matRotation.m11 + Axis.z * matRotation.m21;// + matRotation._42;
            vNewAxis.z = Axis.x * matRotation.m02 + Axis.y * matRotation.m12 + Axis.z * matRotation.m22;// + matRotation._43;
            return vNewAxis;
        }

        #endregion ROTATION_UTILITY
   
    }

    public static class MogreExtensions
    {
        public static Vector3 ConvertLocalToWorldPosition(this Node self, Vector3 localPos)
        {
            return (self._getDerivedOrientation() * localPos * self._getDerivedScale()) + self._getDerivedPosition();
        }
    }

    // Collison CallBack
    class BodyContact : ContactCallback
    {
        MogreWindow _parent;
        public BodyContact(MogreWindow parentform)
        {
            _parent = parentform;
        }
        public override int UserAABBOverlap(ContactMaterial material, Body body0, Body body1, int threadIndex)
        {
            return 1;
        }

        public override void UserProcess(ContactJoint contact, float timestep, int threadIndex)
        {

        
        }
    }
 
}







